package cn.edu.zust.se.service.file.service.impl;

import cn.edu.zust.se.api.entity.File;
import cn.dev33.satoken.stp.StpUtil;
import cn.edu.zust.se.api.clients.DiskClient;
import cn.edu.zust.se.api.entity.File;
import cn.edu.zust.se.api.entity.Folder;
import cn.edu.zust.se.api.entity.bo.FolderBo;
import cn.edu.zust.se.service.file.fastdfs.FastDFSService;
import cn.edu.zust.se.service.file.mapper.FileMapper;
import cn.edu.zust.se.api.entity.bo.FolderBo;
import cn.edu.zust.se.api.entity.vo.FileAndFolderVo;
import cn.edu.zust.se.service.file.mapper.FolderMapper;
import cn.edu.zust.se.service.file.service.FileService;
import cn.edu.zust.se.service.file.service.FolderService;
import cn.edu.zust.se.service.file.utils.FastDFSClientUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class FolderServiceImpl extends ServiceImpl<FolderMapper, Folder> implements FolderService {
    private final FolderMapper folderMapper;
    private final FastDFSClientUtil fastDFSClientUtil;
    private final FileService fileService;
    private final FastDFSService fastDFSService;
    //获取个人网盘的文件夹
    //主页（最外层级相当于一个文件夹 其id=0）
    @Override
    public List<Folder> getFoldersByFolderId(Long folderId, Integer type) {
        LambdaQueryWrapper<Folder> lqw = new LambdaQueryWrapper<>();
        if (type == 2)
        {
            lqw.eq(Folder::getDelFlag, 2);
        }else {
            lqw.eq(Folder::getDelFlag, 0);
        }
        lqw.eq(Folder::getUserId, StpUtil.getLoginIdAsLong());
        lqw.eq(Folder::getParentId, folderId);
        return folderMapper.selectList(lqw);
    }
    private final FileMapper fileMapper;
    @Value("${tmp.path}")
    private String tmpDir;




    @Override
    public ResponseEntity<byte[]> downloadFolder(Long folderId) {
        Folder folder = folderMapper.selectUndeletedFolderById(folderId);
        if (folder == null) {
            return null;
        }

        Tree<String> tree = buildTree(folder.getUserId());
        System.out.println(tree.getName());
        Tree<String> childTree = tree.getNode(folderId.toString());
        System.out.println(childTree.getName());
        Map<Long, String> map = new HashMap<>();
        traverseTreeAndBuildFolder(childTree, map, 0);
        String path = map.get(folderId);
        ZipUtil.zip(path);
        byte[] bytes = FileUtil.readBytes(path + ".zip");
        FileUtil.del(path + ".zip");
        FileUtil.del(path);
        HttpHeaders headers = new HttpHeaders();
        // 获取中文文件夹名
        String folderName = folder.getName();

        // 使用URLEncoder编码文件名
        try {
            String encodedFolderName = URLEncoder.encode(folderName, "UTF-8");
            headers.setContentDispositionFormData("attachment", encodedFolderName + ".zip");
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            return ResponseEntity.ok().headers(headers).body(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    @Override
    public Boolean createFolder(FolderBo bo) {
        Folder folder = BeanUtil.copyProperties(bo, Folder.class);
        Long parentId = folder.getParentId();
        LambdaQueryWrapper<Folder> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Folder::getParentId, parentId);
        lqw.eq(Folder::getName, folder.getName());
        lqw.eq(Folder::getDelFlag, 0);
        Folder existFolder = folderMapper.selectOne(lqw);
        if (existFolder != null) {
            return false;
        }
        return baseMapper.insert(folder) > 0;
    }

    @Override
    public Tree<String> getFolderTree(Long folderId) {
        return null;
    }


    public Tree<String> buildTree(Long userId) {
        List<TreeNode<String>> nodes = CollUtil.newArrayList();
        // 查询用户的根文件夹
        LambdaQueryWrapper<Folder> folderQueryWrapper = new LambdaQueryWrapper<>();
        folderQueryWrapper.eq(Folder::getUserId, userId);
        folderQueryWrapper.eq(Folder::getParentId, 0);
        folderQueryWrapper.eq(Folder::getDelFlag, 0);
        Folder rootFolder = folderMapper.selectOne(folderQueryWrapper);
        nodes.add(new TreeNode<>(rootFolder.getId().toString(), rootFolder.getParentId().toString(), rootFolder.getName(), 0));
        // 递归查询根文件夹下的所有文件夹和文件
        recursiveBuildTree(rootFolder.getId(), nodes);
        // 将查询结果转换为树形结构
        return TreeUtil.buildSingle(nodes, rootFolder.getId().toString());
    }

    private void recursiveBuildTree(Long id, List<TreeNode<String>> nodes) {
        // 查询当前文件夹下的所有文件和子文件夹
        LambdaQueryWrapper<File> fileQueryWrapper = new LambdaQueryWrapper<>();
        fileQueryWrapper.eq(File::getFolderId, id);
        fileQueryWrapper.eq(File::getDelFlag, 0);
        List<File> files = fileMapper.selectList(fileQueryWrapper);

        LambdaQueryWrapper<Folder> folderQueryWrapper = new LambdaQueryWrapper<>();
        folderQueryWrapper.eq(Folder::getParentId, id);
        folderQueryWrapper.eq(Folder::getDelFlag, 0);
        List<Folder> folders = folderMapper.selectList(folderQueryWrapper);

        // 若当前文件夹没有子文件夹也没有文件，结束递归
        if (files.isEmpty() && folders.isEmpty()) {
            return;
        }

        // 将当前文件夹下的文件和子文件夹添加到结果列表
        nodes.addAll(files.stream()
                .map(file -> new TreeNode<>(file.getId().toString(), id.toString(), file.getOriginalName(), 1))
                .collect(Collectors.toList()));

        nodes.addAll(folders.stream()
                .map(folder -> {
                    TreeNode<String> node = new TreeNode<>(folder.getId().toString(), id.toString(), folder.getName(), 0);
                    // 递归查询子文件夹和文件
                    recursiveBuildTree(folder.getId(), nodes);
                    return node;
                })
                .collect(Collectors.toList()));
    }

    private void traverseTreeAndBuildFolder(Tree<String> tree, Map<Long, String> map, int level) {
        Long currentId = Long.parseLong(tree.getId());
        //判断本节点是否为文件夹
        if (level != 0 && ((Integer) tree.getWeight()).compareTo(0) == 0) {
            map.put(currentId, map.get(Long.parseLong(tree.getParent().getId())) + "\\" + tree.getName());
            FileUtil.mkdir(map.get(currentId));
            log.info("创建文件夹{}", map.get(currentId));
        } else if (level == 0 && ((Integer) tree.getWeight()).compareTo(0) == 0) {
            map.put(currentId, tmpDir + "\\" + tree.getName());
            FileUtil.mkdir(map.get(currentId));
            level++;
            log.info("创建文件夹{}", map.get(currentId));
        }
        //判断本节点是否为文件
        else {
            byte[] bytes = fileService.downloadFile(currentId);
            FileUtil.writeBytes(bytes, map.get(Long.parseLong(tree.getParent().getId())) + "\\" + tree.getName());
            log.info("创建文件{}", map.get(Long.parseLong(tree.getParent().getId())) + "\\" + tree.getName());
        }
        //递归出口
        if (!tree.hasChild()) {
            return;
        }
        //递归调用
        int finalLevel = level;
        tree.getChildren().forEach(node -> traverseTreeAndBuildFolder(node, map, finalLevel));
    }


    //文件夹重命名和移动（文件夹更新）
    @Override
    public Boolean updateById(FolderBo folderBo) {
        Folder folder = BeanUtil.copyProperties(folderBo, Folder.class);
        folder.setParentId(folderBo.getParentId());
       return folderMapper.updateById(folder) > 0;
    }
    //文件夹复制
    @Override
    public Boolean copyFolder(Long folderId, Long targetFolderId) {
        FileAndFolderVo data = getFilesAndFolders(folderId, 1);
        // 创建一个新的目标文件夹记录
        Folder oldFolder = folderMapper.selectById(folderId);
        Folder newFolder = new Folder();
        newFolder.setUserId(oldFolder.getUserId());
        newFolder.setParentId(targetFolderId);
        //判断目标文件下的子目录是否有命名重复的文件夹
        FileAndFolderVo dataTarget = getFilesAndFolders(targetFolderId, 1);
        List<Folder> folders = dataTarget.getFolders();
        for (Folder folder : folders) {
            if (folder.getName().equals(oldFolder.getName())) {
                //如果有重复的文件夹则在原文件夹名后加上时间戳
                newFolder.setName(oldFolder.getName()+ "_" + System.currentTimeMillis());
            }else  {
                newFolder.setName(oldFolder.getName());
            }
        }
        // 插入新的目标文件夹记录
        folderMapper.insert(newFolder);
        Long newFolderId = newFolder.getId();
        return data != null && copyFolderRecursively(data, newFolderId);
    }
    //文件夹复制
    private boolean copyFolderRecursively(FileAndFolderVo fileAndFolderVo, Long targetFolderId) {
        // 复制文件
        if (fileAndFolderVo.getFiles() != null) {
            for (File file : fileAndFolderVo.getFiles()) {
                fileService.copyFile(file.getId(), targetFolderId);
            }
        }
        // 递归复制文件夹
        if (fileAndFolderVo.getFolders() != null) {
            for (Folder folder : fileAndFolderVo.getFolders()) {
                // 创建一个新的目标文件夹记录
                Folder newFolder = new Folder();
                newFolder.setUserId(folder.getUserId());
                newFolder.setParentId(targetFolderId);
                newFolder.setName(folder.getName());
                // 插入新的目标文件夹记录
                folderMapper.insert(newFolder);
                Long newFolderId = newFolder.getId();
                // 获取子文件夹的数据
                FileAndFolderVo subFolderData = getFilesAndFolders(folder.getId(), 1);
                // 递归复制文件夹
                if (subFolderData != null && !copyFolderRecursively(subFolderData, newFolderId)) {
                    return false; // 如果递归复制失败，则整个复制过程失败
                }
            }
        }
        return true; // 复制成功
    }

    //文件夹删除（1为放入回收站，2为彻底删除）
    public Boolean delFileAndFolder(Long folderId, Integer type) throws IOException {
        FileAndFolderVo fileAndFolderVo = getFilesAndFolders(folderId, type);
        System.err.println(fileAndFolderVo);
        Boolean b = delFileAndFolderRecursively(fileAndFolderVo, type);
        if (b) {
            return folderMapper.deleteById(folderId) > 0;
        }
        return false;
    }
    @Override
    public FileAndFolderVo getFilesAndFolders(Long folderId, Integer type) {
        FileAndFolderVo fileAndFolderVo = new FileAndFolderVo();
        fileAndFolderVo.setFiles(fileService.getFilesByFolderId(folderId,type));
        fileAndFolderVo.setFolders(getFoldersByFolderId(folderId,type));
        return fileAndFolderVo;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean recycle(Long folderId) {
        Folder folder = baseMapper.selectDeletedFolderById(folderId);
        if (folder == null) {
            return false;
        }
        Long parentId = folder.getParentId();
        // 查询改文件夹不在回收站的父文件夹id
        while (true) {
            Folder deletedFolder = baseMapper.selectDeletedFolderById(parentId);
            if (deletedFolder == null) break;
            parentId = deletedFolder.getParentId();
        }
        //递归恢复子文件夹及文件
        folder.setParentId(parentId);
        recycleFolderRecursively(folder);
        return true;
    }

    @Override
    public boolean move(FolderBo folderBo) {
        Folder folder = folderMapper.selectUndeletedFolderById(folderBo.getId());
        Folder parent = folderMapper.selectUndeletedFolderById(folderBo.getParentId());
        if (folder == null || parent == null) {
            return false;
        }
        folder.setParentId(folderBo.getParentId());
        return folderMapper.updateById(folder) > 0;
    }

    private void recycleFolderRecursively(Folder folder) {
        // 恢复该文件夹
        folder.setDelFlag(0);
        boolean success1 = baseMapper.updateById(folder) > 0;
        if (!success1) {
            throw new RuntimeException("恢复文件夹失败");
        }
        // 恢复该文件夹下的文件
        LambdaQueryWrapper<File> fileQueryWrapper = new LambdaQueryWrapper<>();
        fileQueryWrapper.eq(File::getFolderId, folder.getId());
        fileQueryWrapper.eq(File::getDelFlag, 2);
        List<File> files = fileMapper.selectList(fileQueryWrapper);
        files.stream().forEach(file -> {
            file.setDelFlag(0);
            boolean success2 = fileMapper.updateById(file) > 0;
            if (!success2) {
                throw new RuntimeException("恢复文件失败");
            }
        });
        // 递归恢复子文件夹
        LambdaQueryWrapper<Folder> folderQueryWrapper = new LambdaQueryWrapper<>();
        folderQueryWrapper.eq(Folder::getParentId, folder.getId());
        folderQueryWrapper.eq(Folder::getDelFlag, 2);
        List<Folder> folders = folderMapper.selectList(folderQueryWrapper);
        // 递归出口
        if (folders.isEmpty() && files.isEmpty()) {
            return;
        }
        // 递归调用
        folders.stream().forEach(subFolder -> recycleFolderRecursively(subFolder));
    }


    private Boolean delFileAndFolderRecursively(FileAndFolderVo fileAndFolderVo, Integer type) throws IOException {
        // 删除文件
        for (File file : fileAndFolderVo.getFiles()) {
            if (type == 1) {
                file.setDelFlag(2);
                fileService.updateById(file);
            } else if (type == 2) {
                String url = file.getPath();
                // 找到第一个斜杠的位置
                int firstSlashIndex = url.indexOf("/");
                // 进行一次分割，从第一个斜杠的位置开始
                String result = url.substring(firstSlashIndex+1);
                fastDFSService.deleteFile(result);
                fileService.removeById(file.getId());
            }
        }
        // 递归删除文件夹
        for (Folder folder : fileAndFolderVo.getFolders()) {

            FileAndFolderVo subFolderData = getFilesAndFolders(folder.getId(),type);
            if (subFolderData != null) {
                if (!delFileAndFolderRecursively(subFolderData, type)) {
                    return false; // 如果递归删除失败，则整个删除过程失败
                }
            }
            if (type == 1) {
                folder.setDelFlag(2);
                folderMapper.updateById(folder);
            } else if (type == 2) {
                folderMapper.deleteById(folder.getId());
            }
        }

        return true; // 删除成功
    }

    //删除文件
}
